昨天主要介紹了視窗看門狗和獨立看門狗的差別,今天來看這如何計算,這計算方式再參考手冊裡面有舉例說明,如下圖:
從圖的下方可以看到,他已Tpclk=48MHz來舉例,最下有個式子48000k,這手冊沒標示出來我也不知道位什麼?或許這是常識?...哈哈剛開始懷疑了一下子為甚麼是48000,經過按計算機才確定那是指48M分之1。
WWDG一般用來監測外部干擾或不可預見的邏輯條件,造成的應用程式背離正常的運行序列而產生的軟體故障。
假設一個程式段正常運行的時間是50ms,在運行完這個段程式之後緊接著進行喂狗,如果在規定的時間視窗內還沒有喂狗,那就說明我們監控的程式出故障了,那麼就會產生系統重置,讓程式重新運行。
硬體需兩個LED來觀看餵狗狀態。
bsp_wwdg.h
#ifndef __WWDG_H
#define __WWDG_H
#include "stm32f0xx.h"
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv);
void WWDG_Feed(void);
#endif
宣告兩個函式,初始化WWDG,餵狗
再來看中斷的部分
void WWDG_IRQHandler(void)
{
// 清除中斷標誌位元
WWDG_ClearFlag();
//黃燈亮,點亮LED只是示意性的操作,
//真正使用的時候,這裡應該是做最重要的事情
LED1_ON;
}
#include "./wwdg/bsp_wwdg.h"
static uint8_t wwdg_cnt; //用於記錄看門狗 遞減計數器的值,方便喂狗函數直接使用
static void WWDG_NVIC_Config(void) // WWDG 中斷優先順序初始化
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
在遞減計數器減到0X40的時候,我們開啟了提前喚醒中斷,這個中斷我們稱它為死前中斷或者叫遺囑中斷,在中斷函數裡面我們應該出來,是很重要的事情而且必須得快,因為遞減計數器再減一次,就會產生系統重置。
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{
wwdg_cnt = tr; //保存CNT配置,用在喂狗函數
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // 開啟 WWDG 時鐘
WWDG_SetPrescaler(prv); // 設置預分頻器的值
WWDG_SetWindowValue(wr); // 設置上視窗值
WWDG_Enable(tr); // 設置計數器的值,使能WWDG
WWDG_ClearFlag(); // 清除提前喚醒中斷標誌位元
WWDG_NVIC_Config(); // 配置WWDG中斷優先順序
WWDG_EnableIT(); // 開WWDG 中斷
}
void WWDG_Feed(void) // 喂狗
{
WWDG_SetCounter( wwdg_cnt ); // 喂狗,刷新遞減計數器的值,設置成最大WDG_CNT=0X7F
}
void WWDG_Config,來解釋這函式裡的三個數值要填怎樣的數值
WWDG 配置函數
tr :遞減計時器的值, 取值範圍為:0x7f~0x40,超出範圍會直接復位
wr :視窗值,取值範圍為:0x7f~0x40
prv:預分頻器值,取值可以是
WWDG_Prescaler_1: WWDG counter clock = (PCLK1(45MHz)/4096)/1 約10968Hz 91us
WWDG_Prescaler_2: WWDG counter clock = (PCLK1(45MHz)/4096)/2 約5484Hz 182us
WWDG_Prescaler_4: WWDG counter clock = (PCLK1(45MHz)/4096)/4 約2742Hz 364us
WWDG_Prescaler_8: WWDG counter clock = (PCLK1(45MHz)/4096)/8 約1371Hz 728us
例:tr = 127(0x7f,tr的最大值) wr = 80(0x50, 0x40為最小wr最小值) prv = WWDG_Prescaler_8~728 * (127-80) = 34.2ms < 刷新窗口 < ~728 * 64 = 46.6ms也就是說調用WWDG_Config進行這樣的配置,若在之後的34.2ms前喂狗,系統會重定,在46.6ms後沒有喂狗,系統也會重定。需要在刷新視窗的時間內喂狗,系統才不會重定。再來看main.c
#include "stm32f0xx.h"
#include "bsp_led.h"
#include "bsp_wwdg.h"
int main(void)
{
uint8_t wwdg_tr, wwdg_wr;
LED_GPIO_Config(); // LED_GPIO初始化
LED2_ON(); //LED2量
delay_ms(20);
WWDG_Config(127,80,WWDG_Prescaler_8); // 初始化WWDG
wwdg_wr = WWDG->CFR & 0X7F; //視窗值我們在初始化的時候設置成0x5F,這個值不會改變
while(1)
{
LED2(OFF);
wwdg_tr = WWDG->CR & 0X7F;
if( wwdg_tr < wwdg_wr )
{
WWDG_Feed(); // 喂狗,重新設置計數器的值為最大0X7F
}
}
}
燒入後的動作:
把編譯好的程式下載到開發板,LED2 被點亮一段時間之後熄滅,之後LED2 一直就沒有被點亮過,說明系統沒有產生重定,如果產生重置的話LED2會再被點亮一次。中斷服務程式中的LED1也沒被點亮過,說明喂狗正常。
看門狗的介紹就到這了,目前我在練習韌體還沒實際用到這個功能。